package org.balthie.demo.opensource.org.codehaus.plexus.util;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;

public class DirectoryScanner extends AbstractScanner
{
    public static void main(String[] args)
    {
        DirectoryScanner scanner = new DirectoryScanner();
        scanner.basedir =  new File("E:\\balthie-git\\viomi-gitlab\\viomi-java-architecture\\Modularity-Architecture-trunk\\component-batch\\src\\test\\java");
//        scanner.excludes = new String[] {"%regex[.*java]"};
        
        scanner.includes = new String[] {"%regex[.*groovy]"};
        scanner.scan();
    }
    
  private static final String[] EMPTY_STRING_ARRAY = new String[0];
  protected File basedir;
  protected ArrayList<String> filesIncluded;
  protected ArrayList<String> filesNotIncluded;
  protected ArrayList<String> filesExcluded;
  protected ArrayList<String> dirsIncluded;
  protected ArrayList<String> dirsNotIncluded;
  protected ArrayList<String> dirsExcluded;
  protected ArrayList<String> filesDeselected;
  protected ArrayList<String> dirsDeselected;
  protected boolean haveSlowResults = false;

  private boolean followSymlinks = true;

  protected boolean everythingIncluded = true;

  private final char[][] tokenizedEmpty = MatchPattern.tokenizePathToCharArray("", File.separator);

  public void setBasedir(String basedir)
  {
    setBasedir(new File(basedir.replace('/', File.separatorChar).replace('\\', File.separatorChar)));
  }

  public void setBasedir(File basedir)
  {
    this.basedir = basedir;
  }

  public File getBasedir()
  {
    return this.basedir;
  }

  public void setFollowSymlinks(boolean followSymlinks)
  {
    this.followSymlinks = followSymlinks;
  }

  public boolean isEverythingIncluded()
  {
    return this.everythingIncluded;
  }

  public void scan()
    throws IllegalStateException
  {
    if (this.basedir == null)
    {
      throw new IllegalStateException("No basedir set");
    }
    if (!this.basedir.exists())
    {
      throw new IllegalStateException("basedir " + this.basedir + " does not exist");
    }
    if (!this.basedir.isDirectory())
    {
      throw new IllegalStateException("basedir " + this.basedir + " is not a directory");
    }

    setupDefaultFilters();
    setupMatchPatterns();

    this.filesIncluded = new ArrayList();
    this.filesNotIncluded = new ArrayList();
    this.filesExcluded = new ArrayList();
    this.filesDeselected = new ArrayList();
    this.dirsIncluded = new ArrayList();
    this.dirsNotIncluded = new ArrayList();
    this.dirsExcluded = new ArrayList();
    this.dirsDeselected = new ArrayList();

    if (isIncluded("", this.tokenizedEmpty))
    {
      if (!isExcluded("", this.tokenizedEmpty))
      {
        if (isSelected("", this.basedir))
        {
          this.dirsIncluded.add("");
        }
        else
        {
          this.dirsDeselected.add("");
        }
      }
      else
      {
        this.dirsExcluded.add("");
      }
    }
    else
    {
      this.dirsNotIncluded.add("");
    }
    scandir(this.basedir, "", true);
  }

  protected void slowScan()
  {
    if (this.haveSlowResults)
    {
      return;
    }

    String[] excl = (String[])this.dirsExcluded.toArray(EMPTY_STRING_ARRAY);
    String[] notIncl = (String[])this.dirsNotIncluded.toArray(EMPTY_STRING_ARRAY);

    for (String anExcl : excl)
    {
      if (couldHoldIncluded(anExcl))
        continue;
      scandir(new File(this.basedir, anExcl), anExcl + File.separator, false);
    }

    for (String aNotIncl : notIncl)
    {
      if (couldHoldIncluded(aNotIncl))
        continue;
      scandir(new File(this.basedir, aNotIncl), aNotIncl + File.separator, false);
    }

    this.haveSlowResults = true;
  }

  protected void scandir(File dir, String vpath, boolean fast)
  {
    String[] newfiles = dir.list();

    if (newfiles == null)
    {
      newfiles = EMPTY_STRING_ARRAY;
    }
    String msg;
    if (!this.followSymlinks)
    {
      try
      {
        if (isParentSymbolicLink(dir, null))
        {
          for (String newfile : newfiles)
          {
            String name = vpath + newfile;
            File file = new File(dir, newfile);
            if (file.isDirectory())
            {
              this.dirsExcluded.add(name);
            }
            else
            {
              this.filesExcluded.add(name);
            }
          }
          return;
        }
      }
      catch (IOException ioe)
      {
        msg = "IOException caught while checking for links!";

        System.err.println(msg);
      }
    }

    if (this.filenameComparator != null)
    {
      Arrays.sort(newfiles, this.filenameComparator);
    }

    for (String newfile : newfiles)
    {
      String name = vpath + newfile;
      char[][] tokenizedName = MatchPattern.tokenizePathToCharArray(name, File.separator);
      File file = new File(dir, newfile);
      if (file.isDirectory())
      {
        if (isIncluded(name, tokenizedName))
        {
          if (!isExcluded(name, tokenizedName))
          {
            if (isSelected(name, file))
            {
              this.dirsIncluded.add(name);
              if (fast)
              {
                scandir(file, name + File.separator, fast);
              }
            }
            else
            {
              this.everythingIncluded = false;
              this.dirsDeselected.add(name);
              if ((fast) && (couldHoldIncluded(name)))
              {
                scandir(file, name + File.separator, fast);
              }
            }

          }
          else
          {
            this.everythingIncluded = false;
            this.dirsExcluded.add(name);
            if ((fast) && (couldHoldIncluded(name)))
            {
              scandir(file, name + File.separator, fast);
            }
          }
        }
        else
        {
          this.everythingIncluded = false;
          this.dirsNotIncluded.add(name);
          if ((fast) && (couldHoldIncluded(name)))
          {
            scandir(file, name + File.separator, fast);
          }
        }
        if (fast)
          continue;
        scandir(file, name + File.separator, fast);
      }
      else {
        if (!file.isFile())
          continue;
        if (isIncluded(name, tokenizedName))
        {
          if (!isExcluded(name, tokenizedName))
          {
            if (isSelected(name, file))
            {
              this.filesIncluded.add(name);
            }
            else
            {
              this.everythingIncluded = false;
              this.filesDeselected.add(name);
            }
          }
          else
          {
            this.everythingIncluded = false;
            this.filesExcluded.add(name);
          }
        }
        else
        {
          this.everythingIncluded = false;
          this.filesNotIncluded.add(name);
        }
      }
    }
  }

  protected boolean isSelected(String name, File file)
  {
    return true;
  }

  public String[] getIncludedFiles()
  {
    return (String[])this.filesIncluded.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getNotIncludedFiles()
  {
    slowScan();
    return (String[])this.filesNotIncluded.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getExcludedFiles()
  {
    slowScan();
    return (String[])this.filesExcluded.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getDeselectedFiles()
  {
    slowScan();
    return (String[])this.filesDeselected.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getIncludedDirectories()
  {
    return (String[])this.dirsIncluded.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getNotIncludedDirectories()
  {
    slowScan();
    return (String[])this.dirsNotIncluded.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getExcludedDirectories()
  {
    slowScan();
    return (String[])this.dirsExcluded.toArray(EMPTY_STRING_ARRAY);
  }

  public String[] getDeselectedDirectories()
  {
    slowScan();
    return (String[])this.dirsDeselected.toArray(EMPTY_STRING_ARRAY);
  }

  public boolean isSymbolicLink(File parent, String name)
    throws IOException
  {
    return false;
  }

  public boolean isParentSymbolicLink(File parent, String name)
    throws IOException
  {
    return false;
  }
}